﻿using NLog.Config;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;

namespace MX.Core.Log
{
    //
    // 摘要:
    //     /// Utilities for dealing with NLog.Config.StackTraceUsage values. ///
    internal static class StackTraceUsageUtils
    {
        private static readonly Assembly coreAssembly = typeof(StackTraceUsageUtils).Assembly;

        private static readonly Assembly mscorlibAssembly = typeof(string).Assembly;

        private static readonly Assembly systemAssembly = typeof(Debug).Assembly;

        internal static StackTraceUsage Max(StackTraceUsage u1, StackTraceUsage u2)
        {
            return (StackTraceUsage)Math.Max((int)u1, (int)u2);
        }

        public static int GetFrameCount(this StackTrace strackTrace)
        {
            return strackTrace.FrameCount;
        }

        public static string GetStackFrameMethodName(MethodBase method, bool includeMethodInfo, bool cleanAsyncMoveNext, bool cleanAnonymousDelegates)
        {
            if (method == null)
            {
                return null;
            }
            string text = method.Name;
            Type declaringType = method.DeclaringType;
            if (cleanAsyncMoveNext && text == "MoveNext" && declaringType?.DeclaringType != null && declaringType.Name.StartsWith("<"))
            {
                int num = declaringType.Name.IndexOf('>', 1);
                if (num > 1)
                {
                    text = declaringType.Name.Substring(1, num - 1);
                }
            }
            if (cleanAnonymousDelegates && text.StartsWith("<") && text.Contains("__") && text.Contains(">"))
            {
                int num2 = text.IndexOf('<') + 1;
                int num3 = text.IndexOf('>');
                text = text.Substring(num2, num3 - num2);
            }
            if (includeMethodInfo && text == method.Name)
            {
                text = method.ToString();
            }
            return text;
        }

        public static string GetStackFrameMethodClassName(MethodBase method, bool includeNameSpace, bool cleanAsyncMoveNext, bool cleanAnonymousDelegates)
        {
            if (method == null)
            {
                return null;
            }
            Type declaringType = method.DeclaringType;
            if (cleanAsyncMoveNext && method.Name == "MoveNext" && declaringType?.DeclaringType != null && declaringType.Name.StartsWith("<") && declaringType.Name.IndexOf('>', 1) > 1)
            {
                declaringType = declaringType.DeclaringType;
            }
            if (!includeNameSpace && declaringType?.DeclaringType != null && declaringType.IsNested && declaringType.GetCustomAttribute<CompilerGeneratedAttribute>() != null)
            {
                return declaringType.DeclaringType.Name;
            }
            string text = (!includeNameSpace) ? declaringType?.Name : declaringType?.FullName;
            if (cleanAnonymousDelegates && text != null)
            {
                int num = text.IndexOf("+<>", StringComparison.Ordinal);
                if (num >= 0)
                {
                    text = text.Substring(0, num);
                }
            }
            return text;
        }

        //
        // 摘要:
        //     /// Gets the fully qualified name of the class invoking the calling method, including
        //     the /// namespace but not the assembly. ///
        [MethodImpl(MethodImplOptions.NoInlining)]
        public static string GetClassFullName()
        {
            string empty = string.Empty;
            return GetClassFullName(new StackFrame(2, fNeedFileInfo: false));
        }

        //
        // 摘要:
        //     /// Gets the fully qualified name of the class invoking the calling method, including
        //     the /// namespace but not the assembly. ///
        //
        // 参数:
        //   stackFrame:
        //     StackFrame from the calling method
        //
        // 返回结果:
        //     Fully qualified class name
        public static string GetClassFullName(StackFrame stackFrame)
        {
            string text = LookupClassNameFromStackFrame(stackFrame);
            if (string.IsNullOrEmpty(text))
            {
                text = GetClassFullName(new StackTrace(fNeedFileInfo: false));
            }
            return text;
        }

        private static string GetClassFullName(StackTrace stackTrace)
        {
            StackFrame[] frames = stackTrace.GetFrames();
            for (int i = 0; i < frames.Length; i++)
            {
                string text = LookupClassNameFromStackFrame(frames[i]);
                if (!string.IsNullOrEmpty(text))
                {
                    return text;
                }
            }
            return string.Empty;
        }

        //
        // 摘要:
        //     /// Returns the assembly from the provided StackFrame (If not internal assembly)
        //     ///
        //
        // 返回结果:
        //     Valid asssembly, or null if assembly was internal
        public static Assembly LookupAssemblyFromStackFrame(StackFrame stackFrame)
        {
            MethodBase method = stackFrame.GetMethod();
            if (method == null)
            {
                return null;
            }
            Assembly assembly = method.DeclaringType?.Assembly ?? method.Module?.Assembly;
            if (assembly == coreAssembly)
            {
                return null;
            }
            if (assembly == mscorlibAssembly)
            {
                return null;
            }
            if (assembly == systemAssembly)
            {
                return null;
            }
            return assembly;
        }

        //
        // 摘要:
        //     /// Returns the classname from the provided StackFrame (If not from internal
        //     assembly) ///
        //
        // 参数:
        //   stackFrame:
        //
        // 返回结果:
        //     Valid class name, or empty string if assembly was internal
        public static string LookupClassNameFromStackFrame(StackFrame stackFrame)
        {
            MethodBase method = stackFrame.GetMethod();
            if (method != null && LookupAssemblyFromStackFrame(stackFrame) != null)
            {
                string text = GetStackFrameMethodClassName(method, includeNameSpace: true, cleanAsyncMoveNext: true, cleanAnonymousDelegates: true) ?? method.Name;
                if (!string.IsNullOrEmpty(text) && !text.StartsWith("System.", StringComparison.Ordinal))
                {
                    return text;
                }
            }
            return string.Empty;
        }
    }
}
